package com.ase.哲学家进餐;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author gyhstart
 * @create 2021/2/19 - 18:33
 **/
public class Solution {
    public static void main(String[] args) {

        DiningPhilosophers diningPhilosophers = new DiningPhilosophers();
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            new Thread(() -> {
                try {
                    diningPhilosophers.wantsToEat(finalI,
                            () -> System.out.println("左边"),
                            () -> System.out.println("右边"),
                            () -> System.out.println("吃面"),
                            () -> System.out.println("放下左边"),
                            () -> System.out.println("放下右边"));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }

    static class DiningPhilosophers {

        private ReentrantLock[] lockList;

        private Semaphore sm = new Semaphore(4);

        public DiningPhilosophers() {
            lockList = new ReentrantLock[5];
            for (int i = 0; i < 5; i++) {
                lockList[i] = new ReentrantLock();
            }
        }

        // call the run() method of any runnable to execute its code
        public void wantsToEat(int philosopher,
                               Runnable pickLeftFork,
                               Runnable pickRightFork,
                               Runnable eat,
                               Runnable putLeftFork,
                               Runnable putRightFork) throws InterruptedException {
            // 主要避免死锁问题
            // 1.并行改串行
            // 2.控制数量  >>  最多只能有4个哲学家同时持有叉子

            // 颁发许可
            sm.acquire();

            lockList[philosopher].lock();
            lockList[(philosopher + 1) % 5].lock();

            pickLeftFork.run();
            pickRightFork.run();

            eat.run();

            putLeftFork.run();
            putRightFork.run();

            lockList[philosopher].unlock();
            lockList[(philosopher + 1) % 5].unlock();

            // 回收许可
            sm.release();
        }
    }
}
